home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
PBLIB1
/
UNITS
/
PBDBLIB.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-05-03
|
22KB
|
680 lines
{SECTION ..PbDBLIB }
UNIT PbDBLIB;
INTERFACE
uses CRT, PbCRT, PbMISC, PbOBJS, PbPARMS,
PbXBASE, PbDBOBJ, PbMEMO;
{
Description : Higher level xBase utilities
Author : Howard Richoux
Date : 12/14/93
Last revised: 12/20/93 hnr minor changes
12/23/93 hnr DBCREATE code
Application : IBM PC and compatibles, done in Turbo Pascal 7
Status : Placed in the Public Domain by HNR Software 1/29/1994
Published in: none
}
var PbDBLIBDebug : boolean;
var LChar, RChar, SepChar : char;
var DBFKeytag : string[3]; { ext for index file }
DBFKeySpec : string; { field list for key }
DBFFstring : string; { field list for dump/extracts }
DBFKeyValue : string; { search string }
DBFFlist : HOLD_object; { parsed Fstring in hold array }
DBFKeyMax : integer; { max recs in key file }
Procedure DBFGetParms;
{[DBF] Fetches standard PbDBLIB fields from parms}
Procedure DBFAddParms;
{[DBF] Adds standard PbDBLIB fields from parms}
Function DBFDecodeFldName(var x : DBF_object; nam : string) : integer;
{[DBF] Fetches Field# given field Name}
Procedure DBFDecodeFString(fstring : string;var x : DBF_object;
var flist : HOLD_object);
{[DBF] xlates fstring into field list}
Function DBFFmtDumpRecNum(recno : integer; typ : byte;
trimflag,recnumflag : boolean; between : string) : string;
{[DBF] Formats the record number - for DBDUMP}
Function DBFFmtDumpRec(var x : DBF_object; var flist : HOLD_object;
trimflag,recnumflag : boolean; between : string) : string;
{[DBF] Formats a record from a field list - for DBDUMP}
Procedure DBFDecodeFieldDef(str : string; var name : string;
var fldtyp : char; var ln,decp : integer);
{[DBF] Decodes the ExportHeader format }
Procedure DBFGetFldInfoByNum(var x : DBF_object; n : integer; var name : string;
var fldtyp : char; var ln,decp : integer);
{[DBF] Retrieves info based on FIELD NUMBER }
Procedure DBFGetFldInfoByName(var x : DBF_object; name : string; var n : integer;
var fldtyp : char; var ln,decp : integer);
{[DBF] Retrieves info based on NAME }
Function DBFExportHeaderStr(var x : DBF_object;
var flist : HOLD_object) : string;
{[DBF] Produces "[<FIELDNAM>(<typ><len>),...]" }
Procedure DBFShowStructure(fn : string);
{[DBF] for visual Verification }
Procedure DBFGetClosedFileInfo(fn : string; var recs,fields,recsize : integer;
eof : longint);
{[DBF] File opened then closed }
Function DBFValidDBFFile(fn : string) : boolean;
{[DBF] for program Verification, checks version byte }
Procedure DBFCreateFieldHeaders(var fil : file;dbfspec : string;
var fields,recbytes : integer);
{[DBF] support for DBFCreateFile }
Function DBFCreateFile(dbfname ,dbfspec : string;var err : integer) : boolean;
{[DBF] Creates empty file from DBFSPEC=[aa(c10),bb(n4.2)...] }
Function DBFCloneFile(fn1,fn2 : string) : boolean;
{[DBF] Header duped, no records }
Function DBFZapFile(fname : string) : boolean;
{[DBF] Keeps original as .BAK }
Function DBFCopyRecords(fn1,fn2,keytag,keyspec : string;
var copied,skipped : longint) : boolean;
{[DBF] copies all non deleted from 1 to 2 }
Function DBFSORTFile(fname,keytag,keyspec : string) : boolean;
{[DBF] sorts DBF file based on tag/spec }
IMPLEMENTATION
var dbf1 : KEYED_DBF_object;
var dbf2 : DBF_object;
Function DBFDecodeFldName(var x : DBF_object; nam : string) : integer;
{[DBF] Fetches Field# given field Name}
var s : string;
fld : integer;
begin
s := nam;
if (length(s) > 0) and (s[1] = '#') then
begin
delete(s,1,1);
fld := strint(s);
end
else fld := x.dbf.dbfldno(s);
{ writeln('DBFDecodeFldName ',nam,' ',fld);}
DBFDecodeFldName := fld;
end;
Procedure DBFDecodeFString(fstring : string;var x : DBF_object;
var flist : HOLD_object);
var s,s1,s2 : string;
i,l : integer;
ch : char;
begin
s := UpCaseStr(fstring);
if s = '[*]' then {all fields in order - limit 127}
begin
for i := 1 to x.dbf.no_col do
begin
s1 := '#' + integerstr(i,3);
removeblanks(s1);
flist.append(s1,0);
end;
end
else begin
if s[1] = LChar then delete(s,1,1);
if s[length(s)] = RChar then delete(s,length(s),1);
while length(s) > 0 do
begin
s1 := GetLeftStr(s,SepChar);
s2 := GetDelimitedStr(s1,'(',')');
l := GetINteger(s2);
flist.append(s1,l);
end;
end;
end;
Function DBFFmtDumpRecNum(recno : integer; typ : byte;
trimflag,recnumflag : boolean; between : string) : string;
{[DBF] Formats the record number - for DBDUMP}
var s,s1 : string;
begin
if typ = 0 then s1 := ' '
else if typ = 1 then s1 := 'Rec#'
else if typ = 2 then s1 := '----'
else if typ = 3 then s1 := integerstr(recno,4);
if trimflag then trim(s1);
s := s1+between;
if recnumflag then s := s1 + between
else s := '';
DBFFmtDumpRecNum := s;
end;
Function DBFFmtDumpRec(var x : DBF_object; var flist : HOLD_object;
trimflag,recnumflag : boolean; between : string) : string;
{[DBF] Formats a record from a field list - for DBDUMP}
var s,s1,nam : string;
var j,fld,len : integer;
begin
s := DBFFmtDumpRecNum(x.dbf.db_rec_no,3,trimflag,recnumflag,between);
j := 1;
while (j <= flist.count) and (j <= x.dbf.dbnumfields) do
begin
nam := flist.fetchstrN(j);
fld := DBFDecodeFldName(x,nam);
if fld > 0 then
begin
s1 := x.dbf.dbstr(fld);
len := flist.fetchnumN(j);
if len > 0 then s1 := leftstr(s1,len);
end
else s1 := '';
if trimflag then trim(s1);
s := s + s1 + between;
inc(j);
end;
if j > 1 then delete(s,(length(s)-length(between))+1,length(between));
DBFFmtDumpRec := s;
end;
Procedure DBFDecodeFieldDef(str : string; var name : string;
var fldtyp : char; var ln,decp : integer);
var s,s1 : string;
ch : char;
i : integer;
begin
name := '';fldtyp := 'C'; ln := 0; decp := 0;
s := str;
name := GetLeftStr(s,'(');
if length(s) < 1 then exit;
fldtyp := s[1];
delete(s,1,1);
if s[length(s)] = ')' then delete(s,length(s),1);
s1 := GetLeftStr(s,'.');
ln := strint(s1);
decp := strint(s);
end;
Procedure DBFGetFldInfoByNum(var x : DBF_object; n : integer; var name : string;
var fldtyp : char; var ln,decp : integer);
var s : string;
begin
s := x.exportfielddefn(n);
DBFDecodeFielddef(s,name,fldtyp,ln,decp);
end;
Procedure DBFGetFldInfoByName(var x : DBF_object; name : string; var n : integer;
var fldtyp : char; var ln,decp : integer);
var s : string;
begin
n := x.dbf.dbfldno(name);
s := x.exportfielddefn(n);
DBFDecodeFielddef(s,name,fldtyp,ln,decp);
end;
Function DBFExportHeaderStr(var x : DBF_object;
var flist : HOLD_object) : string;
var i,j,n : integer;
s : string;
begin
s := '[';
n := min(x.dbf.no_col,flist.count);
i := 0;
while (i <= n) do
begin
inc(i);
j := DBFDecodeFldName(x,flist.fetchstrN(i));
s := s + x.exportfielddefn(j);
if i < n then s := s + ',';
end;
s := s + ']';
DBFExportHeaderStr := s;
end;
Procedure DBFShowStructure(fn : string);
var d : XBASE_DBF_object;
begin
d.init(fn,dbREADONLY);
if d.err = 0 then
begin
d.dbshowstruc;
end
else writeln('Unable to open database [',fn,']');
d.done;
end;
Procedure DBFGetClosedFileInfo(fn : string; var recs,fields,recsize : integer;
eof : longint);
var d : XBASE_DBF_object;
begin
d.init(fn,dbREADONLY);
if d.err = 0 then
begin
fields := d.no_col;
recs := d.dbhead.no_rec;
recsize := d.dbhead.rec_bytes;
eof := SizeofFile(fn,'');
end
else writeln('Unable to open database [',fn,']');
d.done;
end;
Function DBFValidDBFFile(fn : string) : boolean;
var d : XBASE_DBF_object;
var fields, recs, recsize : integer;
eof : longint;
begin
DBFValidDBFFile := false;
d.init(fn,dbREADONLY);
if d.err = 0 then
begin
if (d.dbhead.dbvno = 3) or (d.dbhead.dbvno = 131) then
DBFValidDBFFile := true;
end;
d.done;
end;
{PAGE}
Procedure DBFCreateFieldHeaders(var fil : file;dbfspec : string;
var fields,recbytes : integer);
var s,s1,s2,fldnam : string;
var err,numwritten,i : integer;
ch : char;
fld : db4ref_type;
ok : boolean;
begin
fields := 0; recbytes := 1; { delete flag }
s := UpCaseStr(dbfspec);
if s[1] = LChar then delete(s,1,1);
if s[length(s)] = RChar then s[length(s)] := ',';
while length(s) > 0 do
begin
fillchar(fld,sizeof(fld),0);
s1 := GetLeftStr(s,SEPChar);
s2 := GetDelimitedStr(s1,'(',')');
fldnam := s1;
fld.rtype := s2[1];
delete(s2,1,1);
if fld.rtype = 'N' then
begin
i := pos('.',s2);
if i > 0 then
begin
fld.width := strint(leftstr(s2,i-1));
delete(s2,1,i);
fld.decp := strint(s2);
end
else fld.width := strint(s2);
end
else if fld.rtype = 'D' then fld.width := 8
else if fld.rtype = 'M' then fld.width := 10
else fld.width := strint(s2);
recbytes := recbytes + fld.width;
move(s1[1],fld.name,length(s1));
inc(fields);
ok := MyBlockWrite(fil,fld,sizeof(fld),numwritten,err);
end;
{ I still don't know why these 2 extra bytes }
fld.name[1] := chr(13);
fld.name[2] := chr(0);
ok := MyBlockWrite(fil,fld,2,numwritten,err);
end;
Function DBFCreateFile(dbfname ,dbfspec : string;var err : integer) : boolean;
var numwritten,fields,recsize : integer;
var fil : file;
hd : db4head_type;
ok : boolean;
begin
DBFCreateFile := false;
if length(dbfspec) < 3 then
begin
err:=999;
writeln('No Fields specified, Stopping DBCREATE [',dbfspec,']');
exit;
end;
if not MyOpenFileCreate(fil,dbfname,1,err) then exit;
fillchar(hd,sizeof(hd),0);
hd.dbvno := $83;
hd.no_rec := 0;
hd.header_bytes := 32;
SetDateBytes(hd.updyr,hd.updmo,hd.upddy);
if not MyBlockWrite(fil,hd,sizeof(hd),numwritten,err) then
begin ok := MyCloseFile(fil,err); exit; end;
DBFCreateFieldHeaders(fil,dbfspec,fields,recsize);
if not MySeek(fil,0,err) then
begin ok := MyCloseFile(fil,err); exit; end;
hd.header_bytes := (fields+1)*32+2; {32 hdr + fields*32 + 2 extra btyes}
hd.rec_bytes := recsize;
if not MyBlockWrite(fil,hd,sizeof(hd),numwritten,err) then
begin ok := MyCloseFile(fil,err); exit; end;
ok := MyCloseFile(fil,err);
DBFCreateFile := true;
end;
{PAGE}
Function DBFCloneFile(fn1,fn2 : string) : boolean;
{ Copies Structure, not records }
var fname1, fname2 : string;
oldfile, newfile : file;
fhdr : db4head_type; { general file info}
fldhdr : db4ref_type; { holds 1 field definition}
error, numfields : integer;
numread, i : integer;
hdrsize : integer;
begin
DBFCloneFile := false;
fname1 := fn1;
if not DBFValidDBFfile(fname1) then
begin
writeln('Invalid version # - Cannot clone this file [',fname1,']');
exit;
end;
if not MyOpenFileExisting(oldfile,fname1,1,fREADONLY,error) then exit;
if PbDBLIBDebug then
writeln('ok to clone 1 old file found [',fname1,']');
fname2 := fn2;
if not MyOpenFileCreate(newfile,fname2,1,error) then
begin close(oldfile); exit; end;
if PbDBLIBDebug then
writeln('ok to clone 2 new file not found [',fname2,']');
{Copy file header, resetting some variables }
if not MyBlockRead(oldfile,fhdr,sizeof(fhdr),numread,error) then
if (error <> 0) or (numread <> sizeof(fhdr)) then
begin
writeln('Unable to clone file - header read error= ',error,
' numread= ',numread);
exit;
end;
fhdr.no_rec := 0; { no data records}
SetDateBytes(fhdr.updyr,fhdr.updmo,fhdr.upddy); { last update date}
hdrsize := fhdr.header_bytes;
if not MyBlockWrite(newfile,fhdr,sizeof(fhdr),numread,error) then
begin
writeln('Unable to clone file - header read error= ',error,
' numread= ',numread);
exit;
end;
if PbDBLIBDebug then
writeln('new file header written file size=',filesize(newfile));
{ Now copy the field definitions }
numfields := (fhdr.header_bytes-sizeof(fhdr)) div 32;
if PbDBLIBDebug then
writeln('Header bytes = ',fhdr.header_bytes,
' Number of fields= ',numfields);
for i := 1 to numfields do
begin
if MyBlockRead(oldfile,fldhdr,sizeof(fldhdr),numread,error) then
begin
if not MyBlockWrite(newfile,fldhdr,sizeof(fldhdr),
numread,error) then begin end;
end;
end;
fldhdr.name[1] := chr(13);
if not MyBlockWrite(newfile,fldhdr,1,numread,error) then
begin end; { extra bytes for some reason }
if filesize(newfile) < (hdrsize) then
begin
while (filesize(newfile) < (hdrsize)) do
begin
fldhdr.name[1] := chr(0);
if not MyBlockWrite(newfile,fldhdr,1,numread,error) then
begin end; { extra bytes for some reason }
end;
end;
if PbDBLIBDebug then
writeln('done writing header. file size= ',filesize(newfile));
{$I-} close(oldfile); {$I+}
error := IOResult;
if error <> 0 then writeln('Close error (oldfile) ',error);
{$I-} close(newfile); {$I+}
error := IOResult;
if error <> 0 then writeln('Close error (newfile) ',error);
DBFCloneFile := true;
end;
Function DBFZapFile(fname : string) : boolean;
var fn1,fn2 : string;
begin
DBFZapFile := true;
fn1 := fname;
fn2 := fname;
forceext(fn2,'tmp');
erasefile(fn2);
if DBFCloneFile(fn1,fn2) then
begin
if PbDBLIBDebug then writeln('Cloned OK.');
if not ForceRenameToBAK(fn1) then
begin
DBFZapFile := false;
writeln('Unable to back up the original file - Cancelling ZAP',
'[',fn1,']');
end
else begin
if PbDBLIBDebug then
writeln('Renamed to bak [',fn1,'] OK. ');
if not RenameFile(fn2,fname) then
begin
DBFZapFile := false;
writeln('Unable to rename new file [',fn2,'] [',
fname,']');
end
else if PbDBLIBDebug then
writeln('Renamed [',fn2,'] to [',fname,'] OK. ');
end;
end
else begin
DBFZapFile := false;
writeln('Unable to CLONE file - Cancelling ZAP [',fname,']');
end;
end;
Procedure CopyDbf1ToDbf2(var copied,skipped : longint);
var n : longint;
ok : boolean;
begin
copied := 0; skipped := 0;
for n := 1 to dbf1.numrecs do
begin
dbf1.fetchn(n);
if not dbf1.dbf.dbdeleted then
begin
move(dbf1.dbf.dbbuf,dbf2.dbf.dbbuf,dbf2.recsize);
ok := dbf2.append;
if not ok then
begin
writeln('Unable to write record ',dbf2.err);
exit;
end
else inc(copied);
end
else inc(skipped);
end;
end;
Function DBFCopyRecords(fn1,fn2,keytag,keyspec : string;
var copied,skipped : longint) : boolean;
begin
copied := 0;
DBFCopyRecords := false;
dbf1.init(fn1,0,fREADONLY,keytag,keyspec,DBFKeyMax);
if dbf1.opened then
begin
dbf2.init(fn2,0,fREADWRITE);
if dbf2.opened then
begin
CopyDbf1ToDbf2(copied,skipped);
writeln('Copy done coppied= ',copied,' skipped= ',skipped);
dbf2.done;
end;
dbf1.done;
end;
DBFCopyRecords := true;
end;
{PAGE}
{
Notes on SORT:
1. The file being sorted must be named <name>.DBF
The KEYTAG OR KEYSPEC must be specified in the .CFG file
or on the command line. If both are specified, only the DBFKeyTag is
used.
2. Next, the <name>.DBF file is cloned to <name>.NEW. This copies the
structure, but not the records.
3. Now, the .DBF file is opened using the key specified. If a valid KEY
file exists, it is used, otherwise, it is created.
4. The .DBF file is read in key order and written to the .NEW file.
Deleted records are skipped.
5. Both files are closed.
6. <name>.DBF is force renamed to <name>.BAK. <name>.NEW is renamed
to <name>.DBF.
8. Any existing keytag files will be dated prior to the DBF, and will
be re-created next time they are used.
}
Function DBFSORTFile(fname,keytag,keyspec : string) : boolean;
var fn1,fn2 : string;
copied,skipped : longint;
begin
DBFSortFile := true;
fn1 := fname;
fn2 := fname;
forceext(fn2,'NEW');
erasefile(fn2);
if DBFCloneFile(fn1,fn2) then
begin
if PbDBLIBDebug then writeln('Cloned OK.');
if DBFCopyRecords(fn1,fn2,keytag,keyspec,copied,skipped) then
begin
if PbDBLIBDebug then
writeln(copied, ' Records copied OK. ');
if PbDBLIBDebug then
writeln(skipped, ' Records skipped. ');
end
else begin
writeln('Unable to copy records from [',fn1,'] to [',fn2,
'] - Cancelling SORT');
exit;
end;
if not ForceRenameToBAK(fn1) then
begin
DBFSortFile := false;
writeln('Unable to back up the original file - Cancelling Sort',
'[',fn1,']');
end
else begin
if PbDBLIBDebug then
writeln('Renamed to bak [',fn1,'] OK. ');
if not RenameFile(fn2,fname) then
begin
DBFSortFile := false;
writeln('Unable to rename new file [',fn2,'] [',
fname,']');
end
else if PbDBLIBDebug then
writeln('Renamed [',fn2,'] to [',fname,'] OK. ');
end;
end
else begin
DBFSortFile := false;
writeln('Unable to CLONE file - Cancelling Sort [',fname,']');
end;
end;
{PAGE}
Procedure DBFGetParms;
begin
DBFFstring := GetParmStr('FIELDS');
DBFKeySpec := GetParmStr('KEYSPEC');
DBFKeytag := GetParmStr('KEYTAG');
DBFKeyValue := GetParmStr('KEYVALUE');
DBFKeyMax := GetParmNum('INDEXMAX');
end;
Procedure DBFAddParms;
begin
AddParm(1,'FIELDS','[*]'); { all fields in order }
AddParm(1,'KEYSPEC','');
AddParm(1,'KEYVALUE','*'); { match everything }
AddParm(1,'KEYTAG','');
AddParm(1,'INDEXMAX','5000');
end;
Procedure PbDBLIBInit;
begin
DBFFstring := '';
DBFKeySpec := '';
DBFKeyValue := '';
DBFKeytag := '';
DBFKeyMax := 5000;
PbDBLIBDebug := false;
LChar := '[';
RChar := ']';
Sepchar := ',';
end;
begin {initialization}
PbDBLIBinit;
end.